package com.anti.handler;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.anti.commom.annotation.BusinessLog;
import com.anti.commom.api.Result;
import com.anti.commom.api.ResultCode;
import com.anti.commom.constant.CommonConstant;
import com.anti.commom.constant.SymbolConstant;
import com.anti.commom.context.requestno.RequestNoContext;
import com.anti.commom.core.exception.AuthException;
import com.anti.commom.core.exception.BusinessException;
import com.anti.commom.core.utils.RequestUtils;
import com.anti.commom.core.utils.ResponseUtil;
import com.anti.core.context.login.LoginContextHolder;
import com.anti.core.log.LogManager;
import com.anti.modular.sys.auth.pojo.SysLoginUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @Description TODO
 * @Author anTi
 * @Date 2020-10-7
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 拦截认证失败异常
     */

    @ExceptionHandler(AuthException.class)
    public Object authFail(AuthException e) {
        logger.error(">>> 认证异常，请求号为：{}，具体信息为：{}", RequestNoContext.get(), e.getMessage());
        return ResponseUtil.handleError(e.getCode(), e.getErrorMessage());
    }

    /**
     * 拦截参数校验错误异常,JSON传参
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object methodArgumentNotValidException(MethodArgumentNotValidException e) {
        String argNotValidMessage = getArgNotValidMessage(e.getBindingResult());
        logger.error(">>> 参数校验错误异常，请求号为：{}，具体信息为：{}", RequestNoContext.get(), argNotValidMessage);
        return ResponseUtil.handleError(0, argNotValidMessage);

    }



    @ExceptionHandler(Throwable.class)
    public Object exception(HttpServletRequest request,HandlerMethod handlerMethod, Exception exception) {
        Long time = System.currentTimeMillis();
        String message = exception.getMessage();
        exception.printStackTrace();
        Method m = handlerMethod.getMethod();
        Class<?> clazz = handlerMethod.getBeanType();
        String name = clazz.getName();
        String params = JSONUtil.toJsonStr(request.getParameterMap());
        if (exception instanceof BusinessException) {
            this.logger.warn("[{}][{}][{}]:{} ,request parameters:{}", new Object[]{RequestUtils.getRemoteIP(request), time, request.getRequestURI(), message, JSONUtil.toJsonStr(request.getParameterMap())});
            return Result.fail(ResultCode.BUSINESS_SERVER_ERROR,message);
        }else {
            BusinessLog businessLog = null;
            if (m.getAnnotation(BusinessLog.class)!=null){
                businessLog=m.getAnnotation(BusinessLog.class);
            }
            SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUserWithoutException();
            String account = CommonConstant.UNKNOWN;
            if(ObjectUtil.isNotNull(sysLoginUser)) {
                account = sysLoginUser.getAccount();
            }
            //异步记录日志
            LogManager.me().executeGlobalExceptionLog(businessLog,account,name, m.getName(),params,exception);
        }
        this.logger.error("[{}][{}][{}]:{} ,request parameters:{}", new Object[]{RequestUtils.getRemoteIP(request), time, request.getRequestURI(), message, JSONUtil.toJsonStr(request.getParameterMap())});
        return ResponseUtil.handleError(ResultCode.ERROR.getCode(),"服务异常，请联系管理员");

    }



    /**
     * 获取请求参数不正确的提示信息
     * <p>
     * 多个信息，拼接成用逗号分隔的形式
     *
     * @author yubaoshan
     * @date 2020/5/5 16:50
     */
    private String getArgNotValidMessage(BindingResult bindingResult) {
        if (bindingResult == null) {
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder();

        //多个错误用逗号分隔
        List<ObjectError> allErrorInfos = bindingResult.getAllErrors();
        for (ObjectError error : allErrorInfos) {
            stringBuilder.append(SymbolConstant.COMMA).append(error.getDefaultMessage());
        }

        //最终把首部的逗号去掉
        return StrUtil.removePrefix(stringBuilder.toString(), SymbolConstant.COMMA);
    }
}
